﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.DirectoryServices;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;

namespace CommonLibrary
{
    public static class ClSecurity
    {

        #region 散列

        /// <summary>
        /// Sha1散列
        /// </summary>
        /// <param name="in_str"></param>
        /// <returns></returns>
        public static string ClSha1String(this string in_str)
        {
            SHA1 sha1 = new SHA1CryptoServiceProvider();

            byte[] result = sha1.ComputeHash(Encoding.UTF8.GetBytes(in_str));
            return BitConverter.ToString(result).Replace("-", "").ToUpper();
        }

        /// <summary>
        /// MD5散列
        /// </summary>
        /// <param name="in_str"></param>
        /// <returns></returns>
        public static string ClMD5String(this string in_str)
        {
            MD5 md5 = new MD5CryptoServiceProvider();

            byte[] result = md5.ComputeHash(Encoding.UTF8.GetBytes(in_str));
            return BitConverter.ToString(result).Replace("-", "").ToUpper();
        }


        public static string MD5ByUser(string in_user, string in_str)
        {
            return ClMD5String(ClSha1String(in_user.Trim().ToUpper() + in_str.Trim().ToUpper()));
        }

        public static string MD5ByUser(string in_system, string in_user, string in_str)
        {
            return ClMD5String(ClSha1String(in_system.Trim().ToUpper() + in_user.Trim().ToUpper() + in_str.Trim().ToUpper()));
        }

        public static string MD5ByUser(int in_system, string in_user, string in_str)
        {
            return MD5ByUser(Convert.ToString(in_system), in_user, in_str);
        }

        /// <summary>
        /// 整个文件的MD5
        /// </summary>
        /// <param name="in_str"></param>
        /// <returns></returns>
        public static string ClMD5File(this string in_str)
        {
            if (File.Exists(in_str) == false)
            {
                throw new Exception(@"文件“" + in_str + "”不存在。");
            }

            try
            {
                using (FileStream f = new FileStream(in_str, System.IO.FileMode.Open, FileAccess.Read))
                {
                    MD5 md5 = new MD5CryptoServiceProvider();

                    byte[] result = md5.ComputeHash(f);

                    return BitConverter.ToString(result).Replace("-", "").ToUpper();
                }
            }
            catch
            {
                return null;
            }

        }

        /// <summary>
        /// 整个文件的Sha1
        /// </summary>
        /// <param name="in_str"></param>
        /// <returns></returns>
        public static string ClSha1File(this string in_str)
        {
            if (File.Exists(in_str) == false)
            {
                throw new Exception(@"文件“" + in_str + "”不存在。");
            }

            try
            {
                using (FileStream f = new FileStream(in_str, System.IO.FileMode.Open, FileAccess.Read))
                {
                    SHA1 sha1 = new SHA1CryptoServiceProvider();

                    byte[] result = sha1.ComputeHash(f);

                    return BitConverter.ToString(result).Replace("-", "").ToUpper();
                }
            }
            catch
            {
                return null;
            }

        }

        #endregion

        #region 加密

        /// <summary>
        /// 字符串加密
        /// </summary>
        /// <param name="in_str"></param>
        /// <returns></returns>
        public static string ClEncryptString(this string in_str)
        {
            try
            {
                //return ClEncryptString(in_str, "Miugo");
                return ClEncryptString(in_str, "我的电脑@jian");
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        /// <summary>
        /// 字符串加密(带Key)
        /// </summary>
        /// <param name="in_str"></param>
        /// <param name="in_key"></param>
        /// <returns></returns>
        public static string ClEncryptString(this string in_str, string in_key)
        {
            try
            {
                byte[] bytes = ClType.ConvertStringToBytes(in_str);

                #region DES
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] md5_bytes = md5.ComputeHash(ClType.ConvertStringToBytes(in_key));

                byte[] key_bytes = new byte[8];
                for (int i = 0; i < 8; i++)
                {
                    key_bytes[i] = md5_bytes[i];
                }

                byte[] iv_bytes = new byte[8];
                for (int i = 8; i < 16; i++)
                {
                    iv_bytes[i - 8] = md5_bytes[i];
                }
                des.Key = key_bytes;
                des.IV = iv_bytes;
                #endregion

                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);

                cs.Write(bytes, 0, bytes.Length);
                cs.FlushFinalBlock();

                return ClType.ConvertBytesToString64(ms.ToArray());
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }


        public static bool EncryptDataRsa(byte[] in_bytes, string in_key, out byte[] out_bytes)
        {
            out_bytes = null;
            try
            {
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048);
                RSA.FromXmlString(in_key);
                out_bytes = RSA.Encrypt(in_bytes, false);

                if (out_bytes == null) return false;
                return true;
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        public static string EncryptDataRsa(string in_str, string in_key)
        {
            try
            {
                byte[] b1 = System.Text.Encoding.UTF8.GetBytes(in_str);
                byte[] b2;
                if (EncryptDataRsa(b1, in_key, out b2) == false) return null;

                return Convert.ToBase64String(b2);
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }


        public static string ClEncryptStringHigh(this string in_str, string in_A_PublicKey, string in_B_PrivateKey)
        {
            //生成随机密码
            string m_key = ClMD5String("我的电脑" + Guid.NewGuid().ToString());
            m_key = m_key.Substring(m_key.Length - 24);

            //3DES加密原文
            string pwdText = ClEncrypt3DES(in_str, m_key);


            //用in_A_PublicKey加密密钥
            string keyText = EncryptDataRsa(m_key, in_A_PublicKey);

            //用B_PrivateKey签名密钥
            string signText = SignData(m_key, in_B_PrivateKey);

            string splitText = @"949D3724-C430-48C2-981A-A5A8C995A208";

            return keyText + splitText + signText + splitText + pwdText;
        }

        public static string ClEncryptStringHigh(this string in_str, string in_A_Cert, string in_B_Pfx, string in_B_Pfx_Pwd)
        {
            string a_PublicKey = GetCertKey(in_A_Cert);
            string b_PrivateKey = GetPfxKey(in_B_Pfx, in_B_Pfx_Pwd, true);
            return ClEncryptStringHigh(in_str, a_PublicKey, b_PrivateKey);
        }

        #endregion

        #region 解密

        /// <summary>
        /// 解密字符串
        /// </summary>
        /// <param name="in_str"></param>
        /// <returns></returns>
        public static string ClDecryptString(this string in_str)
        {
            try
            {
                //return ClDecryptString(in_str, "Miugo");
                return ClDecryptString(in_str, "我的电脑@jian");
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }

        }

        /// <summary>
        /// 解密字符串(带Key)
        /// </summary>
        /// <param name="in_str"></param>
        /// <param name="in_key"></param>
        /// <returns></returns>
        public static string ClDecryptString(this string in_str, string in_key)
        {
            try
            {
                byte[] bytes = ClType.ConvertStringToBytes64(in_str);

                #region DES
                DESCryptoServiceProvider des = new DESCryptoServiceProvider();
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] md5_bytes = md5.ComputeHash(ClType.ConvertStringToBytes(in_key));

                byte[] key_bytes = new byte[8];
                for (int i = 0; i < 8; i++)
                {
                    key_bytes[i] = md5_bytes[i];
                }

                byte[] iv_bytes = new byte[8];
                for (int i = 8; i < 16; i++)
                {
                    iv_bytes[i - 8] = md5_bytes[i];
                }
                des.Key = key_bytes;
                des.IV = iv_bytes;
                #endregion

                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);

                cs.Write(bytes, 0, bytes.Length);
                cs.FlushFinalBlock();

                return ClType.ConvertBytesToString(ms.ToArray());
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }

        }



        public static bool DecryptDataRsa(byte[] in_bytes, string in_key, out byte[] out_bytes)
        {
            out_bytes = null;
            try
            {
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048);
                RSA.FromXmlString(in_key);
                out_bytes = RSA.Decrypt(in_bytes, false);

                if (out_bytes == null) return false;
                return true;
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        public static string DecryptDataRsa(string in_str, string in_key)
        {
            try
            {
                byte[] b1 = Convert.FromBase64String(in_str);
                byte[] b2;
                if (DecryptDataRsa(b1, in_key, out b2) == false) return null;

                return System.Text.Encoding.UTF8.GetString(b2);
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }


        public static string ClDecryptStringHigh(string in_str, string in_A_PrivateKey, string in_B_PublicKey)
        {
            string splitText = @"949D3724-C430-48C2-981A-A5A8C995A208";
            string[] arr = System.Text.RegularExpressions.Regex.Split(in_str, splitText, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            if (arr.Length != 3) return null;

            //用in_A_PrivateKey解密密钥
            string keyText = DecryptDataRsa(arr[0], in_A_PrivateKey);

            //用in_B_PublicKey验证签名密钥
            if (VerifyData(arr[1], in_B_PublicKey, keyText) == false) return null;

            //3DES解密密文
            return ClDecrypt3DES(arr[2], keyText);
        }

        public static string ClDecryptStringHigh(this string in_str, string in_A_Pfx, string in_A_Pfx_Pwd, string in_B_Cert)
        {
            string a_PrivateKey = GetPfxKey(in_A_Pfx, in_A_Pfx_Pwd, true);
            string b_PublicKey = GetCertKey(in_B_Cert);
            return ClDecryptStringHigh(in_str, a_PrivateKey, b_PublicKey);
        }


        #endregion

        #region 签名

        /// <summary>
        /// 签名
        /// </summary>
        /// <param name="in_bytes"></param>
        /// <param name="in_key"></param>
        /// <param name="out_bytes"></param>
        /// <returns></returns>
        public static bool SignData(byte[] in_bytes, string in_key, out byte[] out_bytes)
        {
            out_bytes = null;
            try
            {
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048);
                RSA.FromXmlString(in_key);
                MD5 md5 = MD5.Create();
                out_bytes = RSA.SignData(in_bytes, md5);

                if (out_bytes == null) return false;
                return true;
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        /// <summary>
        /// 签名
        /// </summary>
        /// <param name="in_str"></param>
        /// <param name="in_key"></param>
        /// <param name="out_str"></param>
        /// <returns></returns>
        public static string SignData(string in_str, string in_key)
        {
            try
            {
                byte[] b1 = System.Text.Encoding.UTF8.GetBytes(in_str);
                byte[] b2;
                if (SignData(b1, in_key, out b2) == false) return null;

                return Convert.ToBase64String(b2);
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        public static string SignDataFromPfx(string in_str, string in_pfx, string in_pwd)
        {
            string privateKey = GetPfxKey(in_pfx, in_pwd, true);
            return SignData(in_str, privateKey);
        }

        public static string SignDataFromPfxWithSource(string in_str, string in_pfx, string in_pwd)
        {
            string str = in_str;

            string privateKey = GetPfxKey(in_pfx, in_pwd, true);
            string singStr = SignData(in_str, privateKey);

            str = str + "949D3724-C430-48C2-981A-A5A8C995A208" + singStr;
            return str;
        }

        #endregion

        #region 验证签名

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="in_bytes"></param>
        /// <param name="in_key"></param>
        /// <param name="in_source"></param>
        /// <returns></returns>
        public static bool VerifyData(byte[] in_bytes, string in_key, byte[] in_source)
        {
            try
            {
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048);
                RSA.FromXmlString(in_key);
                MD5 md5 = MD5.Create();

                return RSA.VerifyData(in_source, md5, in_bytes);
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="in_target"></param>
        /// <param name="in_key"></param>
        /// <param name="in_source"></param>
        /// <returns></returns>
        public static bool VerifyData(string in_target, string in_key, string in_source)
        {
            try
            {
                byte[] bTarget = Convert.FromBase64String(in_target);

                byte[] bSource = System.Text.Encoding.UTF8.GetBytes(in_source);

                if (VerifyData(bTarget, in_key, bSource) == false) return false;

                return true;
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        public static bool VerifyDataFromCert(string in_target, string in_cert, string in_source)
        {
            string publicKey = GetCertKey(in_cert);
            return VerifyData(in_target, publicKey, in_source);
        }

        public static bool VerifyDataFromCertWithSource(string in_str, string in_cert)
        {
            string publicKey = GetCertKey(in_cert);

            string splitText = @"949D3724-C430-48C2-981A-A5A8C995A208";
            string[] arr = System.Text.RegularExpressions.Regex.Split(in_str, splitText, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            if (arr.Length != 2) return false;
            return VerifyData(arr[1], publicKey, arr[0]);
        }

        #endregion


        #region 3DES

        /// <summary>
        /// 3DES加密带KEY
        /// </summary>
        /// <param name="in_str"></param>
        /// <param name="in_key"></param>
        /// <returns></returns>
        public static string ClEncrypt3DES(this string in_str, string in_key)
        {
            try
            {
                string newKey = ClMD5String(in_key).Substring(ClMD5String(in_key).Length - 24);
                TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();

                DES.Key = Encoding.UTF8.GetBytes(newKey);
                DES.Mode = CipherMode.ECB;

                ICryptoTransform DESEncrypt = DES.CreateEncryptor();

                byte[] Buffer = Encoding.UTF8.GetBytes(in_str);
                return Convert.ToBase64String(DESEncrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        /// <summary>
        /// 3DES加密
        /// </summary>
        /// <param name="in_str"></param>
        /// <returns></returns>
        public static string ClEncrypt3DES(this string in_str)
        {
            return ClEncrypt3DES(in_str, "我的电脑@jian");
        }

        /// <summary>
        /// 3DES解密带KEY
        /// </summary>
        /// <param name="in_str"></param>
        /// <param name="in_key"></param>
        /// <returns></returns>
        public static string ClDecrypt3DES(this string in_str, string in_key)
        {
            try
            {
                string newKey = ClMD5String(in_key).Substring(ClMD5String(in_key).Length - 24);
                TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();

                DES.Key = Encoding.UTF8.GetBytes(newKey);
                DES.Mode = CipherMode.ECB;
                DES.Padding = System.Security.Cryptography.PaddingMode.PKCS7;

                ICryptoTransform DESDecrypt = DES.CreateDecryptor();

                byte[] Buffer = Convert.FromBase64String(in_str);
                return Encoding.UTF8.GetString(DESDecrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        /// <summary>
        /// 3DES解密
        /// </summary>
        /// <param name="in_str"></param>
        /// <returns></returns>
        public static string ClDecrypt3DES(this string in_str)
        {
            return ClDecrypt3DES(in_str, "我的电脑@jian");
        }

        #endregion

        /// <summary>
        /// 验证本机用户名和密码
        /// </summary>
        /// <param name="in_user"></param>
        /// <param name="in_pwd"></param>
        /// <returns></returns>
        public static bool CheckWindowsUserPassword(string in_user, string in_pwd)
        {
            string path = "WinNT://" + Environment.MachineName + ",computer";


            DirectoryEntry entry = null;

            #region 先用一个错误的密码刷新缓存（只要成功过一次，更改密码后，立即点，也会正确，可能是连接有缓存）
            try
            {
                entry = new DirectoryEntry(path, in_user, Guid.NewGuid().ToString());
                int trytest = entry.Properties.Count;
            }
            catch { }
            finally
            {
                entry.Close();
                entry.Dispose();
            }
            #endregion


            #region 真正的验证

            try
            {
                entry = new DirectoryEntry(path, in_user, in_pwd);
                int i = entry.Properties.Count;
                return true;
            }
            catch
            {
                return false;
            }
            finally
            {
                entry.Close();
                entry.Dispose();
            }
            #endregion
        }

        #region pfx

        public static string GetPfxKey(string in_pfx, string in_pwd, bool in_PrivateKey)
        {
            try
            {
                string result = "";
                X509Certificate2 pc = new X509Certificate2(in_pfx, in_pwd, X509KeyStorageFlags.Exportable);
                if (in_PrivateKey)
                {
                    result = pc.PrivateKey.ToXmlString(true);
                }
                else
                {
                    result = pc.PublicKey.Key.ToXmlString(false);
                }
                pc = null;
                return result;
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        public static string GetCertKey(string in_cert)
        {
            try
            {
                string result = "";
                X509Certificate2 pc = new X509Certificate2(in_cert);
                result = pc.PublicKey.Key.ToXmlString(false);
                pc = null;
                return result;
            }
            catch (Exception err)
            {
                FileClass.Log(err);
                throw;
            }
        }

        public static string EncryptDataRsaFromCert(string in_str, string in_cert)
        {
            string publicKey = GetCertKey(in_cert);
            return EncryptDataRsa(in_str, publicKey);
        }

        public static string DecryptDataRsaFromPfx(string in_str, string in_pfx, string in_pwd)
        {
            string privateKey = GetPfxKey(in_pfx, in_pwd, true);
            return DecryptDataRsa(in_str, privateKey);
        }

        #endregion


        /// <summary>
        /// 验证Exe调用Dll的PublicKey是否一样
        /// </summary>
        public static void CheckKey()
        {
            byte[] b1 = Assembly.GetEntryAssembly().GetName().GetPublicKey();//第1个Exe的PublicKey
            byte[] b2 = Assembly.GetExecutingAssembly().GetName().GetPublicKey();//自己的PublicKey

            if (BitConverter.ToString(b1).Replace("-", "").CompareTo(BitConverter.ToString(b2).Replace("-", "")) != 0)
            {
                throw new Exception("PublicKey Error!");
            }
        }

        /// <summary>
        /// 生成随机密码
        /// </summary>
        /// <param name="length"></param>
        /// <param name="up"></param>
        /// <param name="low"></param>
        /// <param name="num"></param>
        /// <param name="ch"></param>
        /// <param name="ex"></param>
        /// <returns></returns>
        public static string GenPwd(int length, int up, int low, int num, int ch, string ex)
        {
            try
            {
                if (up + low + num + ch == 0)
                {
                    throw new Exception("元素组合的长度必须大于0");
                }

                if (length < up + low + num + ch)
                {
                    throw new Exception("元素组合的长度大过密码设定的长度");
                }

                MatchCollection matchCollection;
                string pwd = "";
                while (true)
                {
                    pwd = System.Web.Security.Membership.GeneratePassword(length, 0);

                    matchCollection = Regex.Matches(pwd, @"[A-Z]");
                    if (matchCollection.Count < up)
                    {
                        continue;
                    }
                    if ((up == 0) && (matchCollection.Count > 0))
                    {
                        continue;
                    }


                    matchCollection = Regex.Matches(pwd, @"[a-z]");
                    if (matchCollection.Count < low)
                    {
                        continue;
                    }
                    if ((low == 0) && (matchCollection.Count > 0))
                    {
                        continue;
                    }


                    matchCollection = Regex.Matches(pwd, @"[0-9]");
                    if (matchCollection.Count < num)
                    {
                        continue;
                    }
                    if ((num == 0) && (matchCollection.Count > 0))
                    {
                        continue;
                    }


                    matchCollection = Regex.Matches(pwd, @"[\W_]");
                    if (matchCollection.Count < ch)
                    {
                        continue;
                    }
                    if ((ch == 0) && (matchCollection.Count > 0))
                    {
                        continue;
                    }


                    //排除字符串
                    if (ex.ClIsNullOrWhiteSpace() == false)
                    {
                        matchCollection = Regex.Matches(pwd, "[" + ex + "]");
                        if (matchCollection.Count > 0)
                        {
                            continue;
                        }
                    }

                    break;
                }

                return pwd;
            }
            catch (Exception)
            {
                throw;
            }
        }


    }
}
